home *** CD-ROM | disk | FTP | other *** search
- /* DoSCSISynchronousIO.c */
- /*
- * DoSCSIExecIO.c
- * Copyright © 1992-93 Apple Computer Inc. All Rights Reserved.
- *
- * Talk to the Macintosh SCSI Manager 4.3 using the "new" interface. This executes
- * a single SCSI Command on a device using parameters from the INFO record. Note:
- * this command is only used for dialog setup and always executes synchronously
- * with polled I/O and no disconnect.
- *
- * Calling Sequence:
- * OSErr DoSCSISynchronousIO(
- * InfoPtr infoPtr,
- * SCSI_CommandPtr commandPtr,
- * unsigned long scsiFlags,
- * Ptr bufferPtr,
- * unsigned long transferLength
- * );
- * The following information is taken from the InfoRecord:
- * ScsiCmdBlock *pb -- the Scsi Command block
- * unsigned long pbSize -- the size of the command block
- * ProcPtr ioCompletion -- NULL for synch, else asynch
- * DeviceIdent deviceIdent -- bus/target/LUN
- * After completion, the following information is stored in the InfoRecord
- * unsigned short stsByte -- from Status phase
- * unsigned short msgByte -- Command Complete message
- * Return codes:
- * noErr normal
- * statusErr Device returned "Check condition" and SCSI Manager was able
- * to successfully issue Request Sense. There is data in the
- * Sense Record, but you cannot assume that the original request
- * succeeded.
- * paramErr Could not determine the command length.
- * sc... Other error
- */
- #include "SCSIAsyncSample.h"
- #include <GestaltEqu.h>
- #include <Memory.h>
- #include <Events.h>
-
- static void NextFunction(void); /* For HoldMemory size */
- static Boolean IsVirtualMemoryRunning(void);
-
- OSErr
- DoSCSISynchronousIO(
- InfoPtr infoPtr,
- SCSI_CommandPtr commandPtr,
- unsigned long scsiFlags,
- Ptr bufferPtr,
- unsigned long transferLength
- )
- {
- OSErr status;
- register short i;
- union {
- SCSIAbortCommandPB abortCommandPB;
- SCSIResetBusPB resetBusPB;
- SCSIReleaseQPB releaseQPB;
- } pb;
- auto void *vmProtectedStackBase; /* Last local var */
- #define INFO (*infoPtr)
- #define PB (*INFO.pb)
- /*
- * These values are used to compute the size of the stack that we must hold in
- * protected (non-virtual) memory. kSCSIManagerStackEstimate is an estimate.
- */
- #define kSCSILocalVariableSize ( \
- (unsigned long) (((Ptr) &infoPtr) - ((Ptr) &vmProtectedStackBase)) \
- )
- #define kSCSIManagerStackEstimate 512
- #define kSCSIProtectedStackSize (kSCSIManagerStackEstimate + kSCSILocalVariableSize)
-
- status = noErr;
- ClearMemory((Ptr) INFO.pb, INFO.pbSize);
- ClearMemory((Ptr) INFO.vmHoldInfo, sizeof INFO.vmHoldInfo);
- /*
- * Setup the parameter block for the user's request.
- */
- PB.scsiPBLength = INFO.pbSize;
- PB.scsiFunctionCode = SCSIExecIO;
- PB.scsiCompletion = NULL;
- PB.scsiDriverStorage = (unsigned char *) infoPtr; /* for IOCompletion */
- INFO.statusByte = 0xFF; /* Illegal value for debugging */
- PB.scsiTimeout = INFO.completionTimeout;
- PB.scsiDevice = INFO.deviceIdent;
- PB.scsiCDBLength = GetSCSICDBLength(commandPtr);
- if (PB.scsiCDBLength == 0) {
- status = paramErr;
- goto exit;
- }
- /*
- * Copy the command block into the SCSI PB to simplify vm lockdown.
- */
- BlockMove(commandPtr, &PB.scsiCDB, PB.scsiCDBLength);
- /*
- * Specify the transfer direction, if any. scsiFlags should be one of
- * scsiDirectionIn, scsiDirectionOut, or scsiDirectionNone
- */
- PB.scsiFlags = scsiFlags; /* scsiDirectionIn or scsiDirectionOut */
- if (bufferPtr == NULL || transferLength == 0)
- PB.scsiFlags = scsiDirectionNone;
- else {
- /*
- * If the user specified the transfer quantum == 1, select "polled"
- * transfers, otherwise, select "blind."
- */
- PB.scsiTransferType = scsiTransferPolled;
- PB.scsiDataPtr = (unsigned char *) bufferPtr;
- PB.scsiDataLength = transferLength;
- PB.scsiDataType = scsiDataBuffer;
- PB.scsiHandshake[0] = 1;
- PB.scsiHandshake[1] = 0;
- }
- PB.scsiSensePtr = (unsigned char *) &INFO.senseData;
- PB.scsiSenseLength = sizeof INFO.senseData;
- /*
- * The SCSI Manager "freezes" the device queue after a Check Condition
- * (even if AutoSense was enabled). Disable this to prevent hangs.
- */
- PB.scsiFlags |= (scsiDontDisconnect | scsiSIMQNoFreeze);
- /*
- * We are now ready to perform the operation. If virtual memory is active
- * however, we must lock down all memory segments that can be potentially
- * "touched" while the SCSI request is being executed. All of this is
- * needed for applications. For drivers, most of the following can be
- * ignored as the driver code and driver-specific resources are stored in
- * the System Heap, which is always "held" in physical memory.
- */
- if (gVirtualMemoryEnabled) {
- /*
- * Virtual memory is active. Lock all of the memory segments that we
- * need in "real" memory (i.e. non-paged pool) for the duration of the
- * call.
- */
- INFO.vmHoldInfo[kVMFunction].ptr = DoSCSISynchronousIO;
- INFO.vmHoldInfo[kVMFunction].size =
- (unsigned long) NextFunction - (unsigned long) DoSCSISynchronousIO;
- INFO.vmHoldInfo[kVMStack].ptr = (void *)
- (((unsigned long) &vmProtectedStackBase)
- - kSCSIManagerStackEstimate);
- INFO.vmHoldInfo[kVMStack].size = kSCSIProtectedStackSize;
- INFO.vmHoldInfo[kVMParam].ptr = INFO.pb;
- INFO.vmHoldInfo[kVMParam].size = INFO.pbSize;
- if (bufferPtr != NULL) {
- INFO.vmHoldInfo[kVMBuffer].ptr = PB.scsiDataPtr;
- INFO.vmHoldInfo[kVMBuffer].size = PB.scsiDataLength;
- }
- INFO.vmHoldInfo[kVMSense].ptr = PB.scsiSensePtr;
- INFO.vmHoldInfo[kVMSense].size = PB.scsiSenseLength;
- for (i = 0; i < kVMSize; i++) {
- if (INFO.vmHoldInfo[i].ptr != NULL) {
- status = HoldMemory(
- INFO.vmHoldInfo[i].ptr,
- INFO.vmHoldInfo[i].size
- );
- if (status != noErr) {
- while (i < kVMSize)
- INFO.vmHoldInfo[i++].ptr = NULL;
- break;
- }
- }
- }
- if (status != noErr) {
- /*
- * Something failed. Unwind before exiting.
- */
- for (i = 0; i < kVMSize; i++) {
- if (INFO.vmHoldInfo[i].ptr != NULL) {
- (void) UnholdMemory(
- INFO.vmHoldInfo[i].ptr,
- INFO.vmHoldInfo[i].size
- );
- }
- }
- }
- }
- /*
- * Now, just call the New SCSI Manager.
- */
- if (status == noErr) {
- status = SCSIAction((SCSI_PB *) &PB);
- if (PB.scsiCompletion == NULL) {
- /*
- * Synchronous request: The following should be
- * moved to a "default" I/O Completion routine.
- */
- if (status == noErr)
- status = PB.scsiResult;
- /*
- * These should never happen.
- */
- if (status == scsiRequestInProgress) {
- CLEAR(pb.abortCommandPB);
- pb.abortCommandPB.scsiPBLength = sizeof pb.abortCommandPB;
- pb.abortCommandPB.scsiFunctionCode = SCSIAbortCommand;
- pb.abortCommandPB.scsiIOptr = INFO.pb;
- (void) SCSIAction((SCSI_PB *) &pb.abortCommandPB);
- }
- if ((PB.scsiResultFlags & scsiBusNotFree) != 0) {
- CLEAR(pb.resetBusPB);
- pb.resetBusPB.scsiPBLength = sizeof pb.resetBusPB;
- pb.resetBusPB.scsiFunctionCode = SCSIResetBus;
- (void) SCSIAction((SCSI_PB *) &pb.resetBusPB);
- }
- if ((PB.scsiResultFlags & scsiSIMQFrozen) != 0) {
- CLEAR(pb.releaseQPB);
- pb.releaseQPB.scsiPBLength = sizeof pb.releaseQPB;
- pb.releaseQPB.scsiFunctionCode = SCSIReleaseQ;
- (void) SCSIAction((SCSI_PB *) &pb.releaseQPB);
- }
- for (i = 0; i < kVMSize; i++) {
- if (INFO.vmHoldInfo[i].ptr != NULL) {
- (void) UnholdMemory(
- INFO.vmHoldInfo[i].ptr,
- INFO.vmHoldInfo[i].size
- );
- }
- }
- INFO.actualTransferCount =
- PB.scsiDataLength - PB.scsiDataResidual;
- if (status == scsiDataRunError
- && PB.scsiDataResidual != PB.scsiDataLength)
- status = noErr;
- }
- }
- exit: return (status);
- #undef PB
- }
-
- static void NextFunction(void) { } /* Dummy function for MacSCSICommand size */
-